﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ELab.Message
{
    public class EventMessage : IEventMessage
    {
        public EventMessage()
        {
        }

        public EventMessage(byte[] data)
        {
            if (data == null || data.Length < 7 || data[0] != (byte)MessageType.Event || data[5] > 1 || data[6] > 1)
                throw new Exception("Invalidate data bytes of Event message");

            byte[] lengBytes = new byte[] { data[1], data[2], data[3], data[4] };
            int length = BitConverter.ToInt32(lengBytes, 0);
            if (length != data.Length)
                throw new Exception("Invalidate data bytes of Event message");

            int index = 7; //start Data of the Event
            var endIndex = index;

            //If has mouse event
            if (data[5] == 1)
            {
                var mouseEvent = new MessageMouseEventArgs();

                // Gets which mouse button was pressed.
                endIndex += 4;
                var buttonBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int button = BitConverter.ToInt32(buttonBytes, 0);
                mouseEvent.Button = (MouseButtons)button;

                //number button click
                endIndex += 4;
                var clicksBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int clicks = BitConverter.ToInt32(clicksBytes, 0);
                mouseEvent.Clicks = clicks;

                // Gets a signed count of the number of detents the mouse wheel has rotated,
                // multiplied by the WHEEL_DELTA constant. A detent is one notch of the mouse wheel.
                endIndex += 4;
                var deltaBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int delta = BitConverter.ToInt32(deltaBytes, 0);
                mouseEvent.Delta = delta;

                // Gets the x-coordinate of the mouse during the generating mouse event.
                endIndex += 4;
                var xBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int x = BitConverter.ToInt32(xBytes, 0);
                mouseEvent.X = x;

                // Gets the y-coordinate of the mouse during the generating mouse event.
                endIndex += 4;
                var yBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int y = BitConverter.ToInt32(yBytes, 0);
                mouseEvent.Y = y;


                // Gets the active screen x-coordinate of the mouse during the generating mouse event.
                endIndex += 1;
                var buttonStatus = data.Skip(index).Take(endIndex - index).FirstOrDefault();
                index = endIndex;
                mouseEvent.ButtonStatus = buttonStatus;

                // Gets the active screen x-coordinate of the mouse during the generating mouse event.
                endIndex += 4;
                var screenXBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int screenX = BitConverter.ToInt32(screenXBytes, 0);
                mouseEvent.ScreenX = screenX;

                // Gets the active screen y-coordinate of the mouse during the generating mouse event.
                endIndex += 4;
                var screenYBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int screenY = BitConverter.ToInt32(screenYBytes, 0);
                mouseEvent.ScreenY = screenY;

                // Gets the active screen width of the mouse during the generating mouse event.
                endIndex += 4;
                var screenWidthBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int screenWidth = BitConverter.ToInt32(screenWidthBytes, 0);
                mouseEvent.ScreenWidth = screenWidth;

                // Gets the active screen height of the mouse during the generating mouse event.
                endIndex += 4;
                var screenHeightBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                int screenHeight = BitConverter.ToInt32(screenHeightBytes, 0);
                mouseEvent.ScreenHeight = screenHeight;

                this.MouseEvent = mouseEvent;
            }

            //If has key event
            if (data[6] == 1)
            {
                //default keys
                var keyEvent = new MessageKeyEventArgs(Keys.None);

                // Gets a value indicating whether the ALT key was pressed.
                endIndex += 1;
                var altBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.Alt = BitConverter.ToBoolean(altBytes, 0);

                // Gets a value indicating whether the CTRL key was pressed.
                endIndex += 1;
                var ctrlBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.Control = BitConverter.ToBoolean(ctrlBytes, 0);

                // Gets a value indicating whether the SHIFT key was pressed.
                endIndex += 1;
                var shiftBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.Shift = BitConverter.ToBoolean(shiftBytes, 0);

                // Gets or sets a value indicating whether the key event should be passed on
                // to the underlying control.
                endIndex += 1;
                var suppressBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                var suppressKeyPress = BitConverter.ToBoolean(suppressBytes, 0);

                // Gets or sets a value indicating whether the event was handled.
                endIndex += 1;
                var handledBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                var handled = BitConverter.ToBoolean(handledBytes, 0);
                keyEvent.Handled = handled;

                // Gets the keyboard code for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                endIndex += 4;
                var keyCodeBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.KeyCode = (Keys)BitConverter.ToInt32(keyCodeBytes, 0);

                // Gets the key data for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                endIndex += 4;
                var keyDataBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                var keyData = (Keys)BitConverter.ToInt32(keyDataBytes, 0);
                keyEvent.KeyData = keyData;


                // Gets the keyboard value for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                endIndex += 4;
                var keyValueBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.KeyValue = BitConverter.ToInt32(keyValueBytes, 0);


                //     Gets the modifier flags for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                //     event. The flags indicate which combination of CTRL, SHIFT, and ALT keys
                //     was pressed.
                endIndex += 4;
                var keyModifierBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                keyEvent.Modifiers = (Keys)BitConverter.ToInt32(keyModifierBytes, 0);


                // Gets or sets a value key is up / down / press
                endIndex += 1;
                var upDownStatusBytes = data.Skip(index).Take(endIndex - index).ToArray();
                index = endIndex;
                var upDownStatusByte = (upDownStatusBytes == null || upDownStatusBytes.Length != 1) ? (byte)0 : upDownStatusBytes[0];
                keyEvent.UpDownStatus = upDownStatusByte;

                this.KeyEvent = keyEvent;
            }
        }

        public MessageType Type
        {
            get { return MessageType.Event; }
        }

        public MessageMouseEventArgs MouseEvent { get; set; }

        public MessageKeyEventArgs KeyEvent { get; set; }

        public byte[] Data
        {
            get
            {
                var data = new byte[] { (byte)this.Type, 0, 0, 0, 0, 0/*no mouse event*/, 0 /*no key event*/};
                #region Mouse data
                if (MouseEvent != null)
                {
                    //update use mouse event
                    data[5] = 1;

                    // Gets which mouse button was pressed.
                    var mouseButton = BitConverter.GetBytes((int)MouseEvent.Button);
                    data = data.Append<byte>(mouseButton);

                    //number button click
                    var numClick = BitConverter.GetBytes(MouseEvent.Clicks);
                    data = data.Append<byte>(numClick);

                    // Gets a signed count of the number of detents the mouse wheel has rotated,
                    // multiplied by the WHEEL_DELTA constant. A detent is one notch of the mouse wheel.
                    var delta = BitConverter.GetBytes((int)MouseEvent.Delta);
                    data = data.Append<byte>(delta);

                    // Gets the location of the mouse during the generating mouse event.
                    // Gets the x-coordinate of the mouse during the generating mouse event.
                    var x = BitConverter.GetBytes((int)MouseEvent.X);
                    data = data.Append<byte>(x);

                    // Gets the y-coordinate of the mouse during the generating mouse event.
                    var y = BitConverter.GetBytes((int)MouseEvent.Y);
                    data = data.Append<byte>(y);

                    // Gets the mouse button status event - up / down.
                    var buttonStatus = MouseEvent.ButtonStatus;
                    data = data.Append<byte>(buttonStatus);

                    // Gets the active screen x-coordinate of the mouse during the generating mouse event.
                    var screenX = BitConverter.GetBytes((int)MouseEvent.ScreenX);
                    data = data.Append<byte>(screenX);

                    // Gets the active screen y-coordinate of the mouse during the generating mouse event.
                    var screenY = BitConverter.GetBytes((int)MouseEvent.ScreenY);
                    data = data.Append<byte>(screenY);

                    // Gets the active screen width of the mouse during the generating mouse event.
                    var screenWidth = BitConverter.GetBytes((int)MouseEvent.ScreenWidth);
                    data = data.Append<byte>(screenWidth);

                    // Gets the active screen height of the mouse during the generating mouse event.
                    var screenHeight = BitConverter.GetBytes((int)MouseEvent.ScreenHeight);
                    data = data.Append<byte>(screenHeight);

                }
                #endregion

                #region Key data
                if (KeyEvent != null)
                {
                    //update use keys event
                    data[6] = 1;

                    // Gets a value indicating whether the ALT key was pressed.
                    var keyAlt = BitConverter.GetBytes(KeyEvent.Alt); //use Alt key?
                    data = data.Append<byte>(keyAlt);

                    // Gets a value indicating whether the CTRL key was pressed.
                    var keyCtrl = BitConverter.GetBytes(KeyEvent.Control);
                    data = data.Append<byte>(keyCtrl);

                    // Gets a value indicating whether the SHIFT key was pressed.
                    var keyShift = BitConverter.GetBytes(KeyEvent.Shift);
                    data = data.Append<byte>(keyShift);

                    //     Gets or sets a value indicating whether the key event should be passed on
                    //     to the underlying control.
                    var keySuppress = BitConverter.GetBytes(KeyEvent.SuppressKeyPress);
                    data = data.Append<byte>(keySuppress);

                    // Gets or sets a value indicating whether the event was handled.
                    var keyHandled = BitConverter.GetBytes(KeyEvent.Handled);
                    data = data.Append<byte>(keyHandled);

                    // Gets the keyboard code for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                    var keyCode = BitConverter.GetBytes((int)KeyEvent.KeyCode);
                    data = data.Append<byte>(keyCode);

                    // Gets the key data for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                    var keyData = BitConverter.GetBytes((int)KeyEvent.KeyData);
                    data = data.Append<byte>(keyData);

                    // Gets the keyboard value for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                    var keyValue = BitConverter.GetBytes(KeyEvent.KeyValue);
                    data = data.Append<byte>(keyValue);

                    //     Gets the modifier flags for a System.Windows.Forms.Control.KeyDown or System.Windows.Forms.Control.KeyUp
                    //     event. The flags indicate which combination of CTRL, SHIFT, and ALT keys
                    //     was pressed.
                    var keyModifiers = BitConverter.GetBytes((int)KeyEvent.Modifiers);
                    data = data.Append<byte>(keyModifiers);

                    //Gets a value indicating whether the key was up / down / press.
                    //default 0, if key down 1; key up 2; key press 3.
                    var keyUpDownStatus = BitConverter.GetBytes(KeyEvent.UpDownStatus);
                    data = data.Append<byte>(keyUpDownStatus);
                }
                #endregion

                //Update length of message
                var bytesLength = BitConverter.GetBytes(data.Length);
                bytesLength.CopyTo(data, 1);

                return data;
            }
        }
    }
}
